package cn.lzg.common.core.codec;

import java.util.List;

import cn.lzg.common.core.model.Request;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

/**
 * 数据包解码器
 * 
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+
 * |  包头	|  模块号   | 命令号   |  长度    |  数据       |
 * +——----——+——-----——+——----——+——----——+——-----——+
 * </pre>
 * 
 * 包头4字节 模块号2字节 命令号2字节 长度4字节(数据部分占有字节数量)
 * 
 *
 */
public class RequestDecoder extends ByteToMessageDecoder {
	/*
	 * 数据包基础长度
	 */
	public static int BASE_LENTH = 4 + 2 + 2 + 4;

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
		System.out.println("解码");
		while (true) {
			if (buffer.readableBytes() >= BASE_LENTH) {
				// 第一个可读数据包的起始位置
				int beginIndex;

				// 循环找出包头位置
				while (true) {
					// 记录包头位置
					beginIndex = buffer.readerIndex();

					// 标记
					buffer.markReaderIndex();
					if (buffer.readInt() == Constants.HEADER_FLAG) {
						break;
					}

					// 单字节读取，预防错过包头
					buffer.resetReaderIndex();
					buffer.readByte();

					if (buffer.readableBytes() < BASE_LENTH) {
						return;
					}
				} // while

				// 读取模块号命令号
				short module = buffer.readShort();
				short cmd = buffer.readShort();

				// 读取数据长度
				int len_data = buffer.readInt();
				//数据长度小于0，说明数据包出错，关闭通道
				if (len_data < 0) {
					ctx.channel().close();
				}
				//buffer中可读数据小于数据长度，数据未完全到达，重置读索引并返回
				if(buffer.readableBytes() < len_data) {
					buffer.readerIndex(beginIndex);
					return;
				}
				//读取数据
				byte[] data = new byte[len_data];
				buffer.readBytes(data);
				
				//封装request消息
				Request message = new Request();
				message.setModule(module);
				message.setCmd(cmd);
				message.setData(data);
				
				//交给下一个handler处理
				out.add(message);
			}else {//如果数据包长度小于基础长度
				break;
			}
		}
		
		//数据包不完整，等待接收
		return;
	}

}
